home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / OpenURL / Developer / Source / library_util.c < prev    next >
C/C++ Source or Header  |  1999-09-26  |  12KB  |  587 lines

  1. /* 
  2. ** openurl.library - universal URL display and browser launcher library
  3. ** Written by Troels Walsted Hansen <troels@thule.no>
  4. ** Placed in the public domain.
  5. **
  6. ** Module with utility functions used by the other library functions.
  7. */
  8.  
  9. #include "library_common.h"
  10. #include "library_api.h"
  11. #include "library_prefs.h"
  12. #include "library_util.h"
  13. #include "handler.h"
  14.  
  15. /**************************************************************************
  16. *
  17. * Definitions.
  18. *
  19. */
  20.  
  21. #define FINDPORT_NUM  100  /* how many FindPort() to do while waiting */
  22. #define FINDPORT_TIME  10  /* how many seconds to spread those FindPort() over */
  23.  
  24. struct PlaceHolder
  25. {
  26.     char ph_Char;
  27.     char *ph_String;
  28. };
  29.  
  30. /**************************************************************************
  31. *
  32. * Prototypes.
  33. *
  34. */
  35.  
  36. static STRPTR ExpandPlaceHolders(STRPTR template, struct PlaceHolder *ph, int num);
  37. static BOOL WriteToFile(STRPTR filename, STRPTR str);
  38. static STRPTR WaitForRexxPort(STRPTR port);
  39. static STRPTR FindRexxPort(struct List *list, STRPTR name);
  40. static BOOL SendRexxMsg(struct MsgPort *replyport, STRPTR rxport, STRPTR rxcmd);
  41.  
  42. /**************************************************************************
  43. *
  44. * Externally visible functions.
  45. *
  46. */
  47.  
  48. BOOL SendToBrowser(STRPTR url, struct List *portlist, struct MsgPort *mp, 
  49.                    BOOL Show, BOOL ToFront, BOOL NewWindow, BOOL Launch)
  50. {
  51.     BOOL retval = FALSE;
  52.     STRPTR cmd = NULL;
  53.     struct PlaceHolder ph[1];
  54.     struct URL_BrowserNode *bn;
  55.  
  56.     /* set up the placeholder mapping */
  57.  
  58.     ph[0].ph_Char = 'u'; ph[0].ph_String = url;
  59.  
  60.     /* try to find one of the browsers in the list */
  61.  
  62.     for(bn = (struct URL_BrowserNode *)Prefs->up_BrowserList.mlh_Head;
  63.         bn->ubn_Node.mln_Succ;
  64.         bn = (struct URL_BrowserNode *)bn->ubn_Node.mln_Succ)
  65.     {
  66.         STRPTR port = FindRexxPort(portlist, bn->ubn_Port);
  67.         if(port)
  68.         {
  69.             /* send uniconify msg */
  70.  
  71.             if(Show && *bn->ubn_ShowCmd)
  72.                 SendRexxMsg(mp, port, bn->ubn_ShowCmd);
  73.  
  74.             /* send screentofront command */
  75.  
  76.             if(ToFront && *bn->ubn_ToFrontCmd)
  77.                 SendRexxMsg(mp, port, bn->ubn_ToFrontCmd);
  78.  
  79.             /* try sending openurl msg */
  80.  
  81.             if(!(cmd = ExpandPlaceHolders(NewWindow ? bn->ubn_OpenURLWCmd : bn->ubn_OpenURLCmd, ph, 1)))
  82.                 goto done;
  83.  
  84.             if(!(retval = SendRexxMsg(mp, port, cmd)))
  85.             {
  86.                 FreeVec(cmd);
  87.                 cmd = NULL;
  88.             }
  89.             else goto done;
  90.         }
  91.     }
  92.  
  93.     /* no running browser, launch a new one */
  94.  
  95.     if(!Launch) goto done;
  96.  
  97.     for(bn = (struct URL_BrowserNode *)Prefs->up_BrowserList.mlh_Head;
  98.         bn->ubn_Node.mln_Succ;
  99.         bn = (struct URL_BrowserNode *)bn->ubn_Node.mln_Succ)
  100.     {
  101.         BOOL startonly;
  102.         STRPTR filepart;
  103.         char c = '\0';
  104.         BPTR lock;
  105.         LONG error;
  106.  
  107.         if(!*bn->ubn_Path) continue;
  108.  
  109.         /* compose commandline */
  110.  
  111.         if(strstr(bn->ubn_Path, "%u"))
  112.             startonly = TRUE;
  113.         else
  114.             startonly = FALSE;
  115.  
  116.         if(!(cmd = ExpandPlaceHolders(bn->ubn_Path, ph, 1)))
  117.             goto done;
  118.  
  119.         filepart = FilePart(bn->ubn_Path);
  120.  
  121.         if(filepart)
  122.         {
  123.             c         = *filepart;
  124.             *filepart = '\0';
  125.         }
  126.  
  127.         lock = Lock(bn->ubn_Path, ACCESS_READ);
  128.  
  129.         if(filepart) *filepart = c;
  130.  
  131.         /* start the browser */
  132.  
  133.         error = SystemTags(cmd, SYS_Asynch,    TRUE,
  134.                                 SYS_Input,     Open("NIL:", MODE_NEWFILE),
  135.                                 SYS_Output,    NULL,
  136.                          lock ? NP_CurrentDir : TAG_IGNORE, lock,
  137.                                 TAG_DONE);
  138.  
  139.         FreeVec(cmd);
  140.         cmd = NULL;
  141.         
  142.         if(error)
  143.         {
  144.             if(lock) UnLock(lock);
  145.             continue;
  146.         }
  147.  
  148.         if(!startonly)
  149.         {
  150.             STRPTR rxport;
  151.  
  152.             /* send urlopen command */
  153.  
  154.             if(!(cmd = ExpandPlaceHolders(bn->ubn_OpenURLCmd, ph, 1)))
  155.                 goto done;
  156.  
  157.             /* wait for the port to appear */
  158.  
  159.             if((rxport = WaitForRexxPort(bn->ubn_Port)))
  160.                 retval = SendRexxMsg(mp, rxport, cmd);
  161.  
  162.             break;
  163.         }
  164.         else
  165.         {
  166.             retval = TRUE;
  167.             break;
  168.         }
  169.     }
  170.  
  171. done:
  172.     if(cmd) FreeVec(cmd);
  173.     return(retval);
  174. }
  175.  
  176. /**************************************************************************/
  177.  
  178. BOOL SendToMailer(STRPTR url, struct List *portlist, struct MsgPort *mp, 
  179.                   BOOL Show, BOOL ToFront, BOOL Launch)
  180. {
  181.     BOOL retval = FALSE, written = FALSE;
  182.     struct PlaceHolder ph[5];
  183.     STRPTR start, end, address = NULL, subject = NULL, body = NULL, cmd = NULL;
  184.     char filename[32];
  185.     struct URL_MailerNode *mn;
  186.  
  187.     /* parse the URL "mailto:user@host.domain?subject=Subject?body=Body" */
  188.  
  189.     start = url;
  190.  
  191.     while(start)
  192.     {
  193.         STRPTR *tag = NULL;
  194.         int offset = 1;
  195.  
  196.         if(!strnicmp(start, "mailto:", 7))
  197.         {
  198.             tag = &address;
  199.             offset = 7;
  200.         }
  201.         else if(!strnicmp(start, "?subject=", 9))
  202.         {
  203.             tag = &subject;
  204.             offset = 9;
  205.         }
  206.         else if(!strnicmp(start, "?body=", 6))
  207.         {
  208.             tag = &body;
  209.             offset = 6;
  210.         }
  211.  
  212.         end = strchr(start + offset, '?');
  213.  
  214.         if(tag && !*tag)
  215.         {
  216.             if(end) *end = '\0';
  217.  
  218.             if(!(*tag = AllocVec(strlen(start + offset) + 1, MEMF_ANY)))
  219.                 goto done;
  220.  
  221.             strcpy(*tag, start + offset);
  222.  
  223.             if(end) *end = '?';
  224.         }
  225.  
  226.         start = end;
  227.     }
  228.  
  229.     if(body)
  230.         SPrintf(filename, "T:OpenURL-MailBody.%08lx", FindTask(NULL));
  231.     else
  232.     {
  233.         written = TRUE;
  234.         strcpy(filename, "NIL:");
  235.     }
  236.  
  237.     /* set up the placeholder mapping */
  238.  
  239.     ph[0].ph_Char = 'a'; ph[0].ph_String = address ? address : (STRPTR)"";
  240.     ph[1].ph_Char = 's'; ph[1].ph_String = subject ? subject : url;
  241.     ph[2].ph_Char = 'b'; ph[2].ph_String = body ? body : (STRPTR)"";
  242.     ph[3].ph_Char = 'f'; ph[3].ph_String = filename;
  243.     ph[4].ph_Char = 'u'; ph[4].ph_String = url;
  244.  
  245.     /* try to find one of the mailers in the list */
  246.  
  247.     for(mn = (struct URL_MailerNode *)Prefs->up_MailerList.mlh_Head;
  248.         mn->umn_Node.mln_Succ;
  249.         mn = (struct URL_MailerNode *)mn->umn_Node.mln_Succ)
  250.     {
  251.         STRPTR port = FindRexxPort(portlist, mn->umn_Port);
  252.  
  253.         if(port)
  254.         {
  255.             /* send uniconify msg */
  256.  
  257.             if(Show && *mn->umn_ShowCmd)
  258.                 SendRexxMsg(mp, port, mn->umn_ShowCmd);
  259.  
  260.             /* send screentofront command */
  261.  
  262.             if(ToFront && *mn->umn_ToFrontCmd)
  263.                 SendRexxMsg(mp, port, mn->umn_ToFrontCmd);
  264.  
  265.             /* write to temp file */
  266.  
  267.             if(!written && strstr(mn->umn_WriteMailCmd, "%f"))
  268.                 written = WriteToFile(filename, body);
  269.  
  270.             /* try sending writemail msg */
  271.  
  272.             if(!(cmd = ExpandPlaceHolders(mn->umn_WriteMailCmd, ph, 5)))
  273.                 goto done;
  274.  
  275.             if(!(retval = SendRexxMsg(mp, port, cmd)))
  276.             {
  277.                 FreeVec(cmd);
  278.                 cmd = NULL;
  279.             }
  280.             else goto done;
  281.         }
  282.     }
  283.  
  284.     /* no running browser, launch a new one */
  285.  
  286.     if(!Launch) goto done;
  287.  
  288.     for(mn = (struct URL_MailerNode *)Prefs->up_MailerList.mlh_Head;
  289.         mn->umn_Node.mln_Succ;
  290.         mn = (struct URL_MailerNode *)mn->umn_Node.mln_Succ)
  291.     {
  292.         BOOL startonly;
  293.         STRPTR filepart;
  294.         char c = '\0';
  295.         BPTR lock;
  296.         LONG error;
  297.  
  298.         if(!*mn->umn_Path) continue;
  299.  
  300.         /* compose commandline */
  301.  
  302.         if(strstr(mn->umn_Path, "%a"))
  303.             startonly = TRUE;
  304.         else
  305.             startonly = FALSE;
  306.  
  307.         if(!written && strstr(mn->umn_Path, "%f"))
  308.             written = WriteToFile(filename, body);
  309.  
  310.         if(!(cmd = ExpandPlaceHolders(mn->umn_Path, ph, 5)))
  311.             goto done;
  312.         
  313.         filepart = FilePart(mn->umn_Path);
  314.  
  315.         if(filepart)
  316.         {
  317.             c         = *filepart;
  318.             *filepart = '\0';
  319.         }
  320.  
  321.         lock = Lock(mn->umn_Path, ACCESS_READ);
  322.  
  323.         if(filepart) *filepart = c;
  324.  
  325.         /* start the mailer */
  326.  
  327.         error = SystemTags(cmd, SYS_Asynch,    TRUE,
  328.                                 SYS_Input,     Open("NIL:", MODE_NEWFILE),
  329.                                 SYS_Output,    NULL,
  330.                          lock ? NP_CurrentDir : TAG_IGNORE, lock,
  331.                                 TAG_DONE);
  332.  
  333.         FreeVec(cmd);
  334.         cmd = NULL;
  335.         
  336.         if(error)
  337.         {
  338.             if(lock) UnLock(lock);
  339.             continue;
  340.         }
  341.  
  342.         if(!startonly)
  343.         {
  344.             STRPTR rxport;
  345.  
  346.             /* send write mail command */
  347.  
  348.             if(!written && strstr(mn->umn_WriteMailCmd, "%f"))
  349.                 written = WriteToFile(filename, body);
  350.  
  351.             if(!(cmd = ExpandPlaceHolders(mn->umn_WriteMailCmd, ph, 5)))
  352.                 goto done;
  353.  
  354.             /* wait for the port to appear */
  355.  
  356.             if((rxport = WaitForRexxPort(mn->umn_Port)))
  357.                 retval = SendRexxMsg(mp, rxport, cmd);
  358.  
  359.             break;
  360.         }
  361.         else
  362.         {
  363.             retval = TRUE;
  364.             break;
  365.         }
  366.     }
  367.  
  368. done:
  369.     if(cmd)     FreeVec(cmd);
  370.     if(body)    FreeVec(body);
  371.     if(subject) FreeVec(subject);
  372.     if(address) FreeVec(address);
  373.  
  374.     return(retval);
  375. }
  376.  
  377. /**************************************************************************/
  378.  
  379. BOOL CopyList(struct List *dst, struct List *src, ULONG size)
  380. {
  381.     struct Node *n, *new;
  382.  
  383.     /* copy src list into dst, and return success */
  384.  
  385.     for(n = src->lh_Head; n->ln_Succ; n = n->ln_Succ)
  386.     {
  387.         if(!(new = AllocMem(size, MEMF_ANY)))
  388.         {
  389.             FreeList(dst, size);
  390.             return(FALSE);
  391.         }
  392.  
  393.         memcpy(new, n, size);
  394.         AddTail(dst, new);
  395.     }
  396.  
  397.     return(TRUE);
  398. }
  399.  
  400. /**************************************************************************/
  401.  
  402. VOID FreeList(struct List *list, ULONG size)
  403. {
  404.     struct Node *n;
  405.  
  406.     while((n = RemHead(list)))
  407.         FreeMem(n, size);
  408. }
  409.  
  410. /**************************************************************************/
  411.  
  412. BOOL isdigits(STRPTR str)
  413. {
  414.     for(;;)
  415.     {
  416.         if(!*str)
  417.             return(TRUE);
  418.         else if(!isdigit(*str))
  419.             return(FALSE);
  420.  
  421.         str++;
  422.     }
  423. }
  424.  
  425. /**************************************************************************/
  426.  
  427. VOID SPrintf(STRPTR to, STRPTR fmt, ...)
  428. {
  429.     static ULONG fmtfunc = 0x16C04E75;
  430.      RawDoFmt(fmt, &fmt + 1, (APTR)&fmtfunc, to);
  431. }
  432.  
  433. /**************************************************************************
  434. *
  435. * Local functions.
  436. *
  437. */
  438.  
  439. static STRPTR ExpandPlaceHolders(STRPTR template, struct PlaceHolder *ph, int num)
  440. {
  441.     STRPTR p, result;
  442.     int i, length = 0;
  443.  
  444.     /* calculate length of result string */
  445.  
  446.     for(p = template; *p; p++)
  447.     {
  448.         for(i = 0; i < num; i++)
  449.         {
  450.             if((*p == '%') && (*(p + 1)== ph[i].ph_Char))
  451.                 length += strlen(ph[i].ph_String);
  452.         }
  453.         length++;
  454.     }
  455.  
  456.     /* allocate result string */
  457.  
  458.     if(!(result = AllocVec(length + 1, MEMF_PUBLIC)))
  459.         return(NULL);
  460.  
  461.     /* perform substitution */
  462.  
  463.     for(p = result; *template; template++)
  464.     {
  465.         for(i = 0; i < num; i++)
  466.             if((*template == '%') && (*(template + 1)== ph[i].ph_Char))
  467.                 break;
  468.  
  469.         if(i < num)
  470.         {
  471.             strcpy(p, ph[i].ph_String);
  472.             p += strlen(ph[i].ph_String);
  473.             template++;
  474.             continue;
  475.         }
  476.  
  477.         *p++ = *template;
  478.     }
  479.  
  480.     *p = '\0';
  481.  
  482.     return(result);
  483. }
  484.  
  485. /**************************************************************************/
  486.  
  487. static BOOL WriteToFile(STRPTR filename, STRPTR str)
  488. {
  489.     BOOL retval = FALSE;
  490.     BPTR fh;
  491.     LONG len = strlen(str);
  492.  
  493.     if((fh = Open(filename, MODE_NEWFILE)))
  494.     {
  495.         if(Write(fh, str, len) == len)
  496.             retval = TRUE;
  497.  
  498.         Close(fh);
  499.     }
  500.  
  501.     return(retval);
  502. }
  503.  
  504. /**************************************************************************/
  505.  
  506. static STRPTR WaitForRexxPort(STRPTR port)
  507. {
  508.     LONG i, delay;
  509.  
  510.     /* (busy) wait for the port to appear */
  511.  
  512.     delay = (FINDPORT_TIME * TICKS_PER_SECOND) / FINDPORT_NUM;
  513.  
  514.     for(i = 0; i < FINDPORT_NUM; i++)
  515.     {
  516.         STRPTR rxport;
  517.  
  518.         Forbid();
  519.         rxport = FindRexxPort(&SysBase->PortList, port);
  520.         Permit();
  521.  
  522.         if(rxport) return(rxport);
  523.  
  524.         if(SetSignal(0, 0) & SIGBREAKF_CTRL_C)
  525.             return(NULL);
  526.     
  527.         Delay(delay);
  528.     }
  529.  
  530.     return(NULL);
  531. }
  532.  
  533. /**************************************************************************/
  534.  
  535. static STRPTR FindRexxPort(struct List *list, STRPTR name)
  536. {
  537.     struct Node *n;
  538.     ULONG len;
  539.  
  540.     /* find a rexx port, allowing a .<number> extension */
  541.  
  542.     len = strlen(name);
  543.  
  544.     for(n = list->lh_Head; n->ln_Succ; n = n->ln_Succ)
  545.     {
  546.         if(n->ln_Name && !strncmp(n->ln_Name, name, len) &&
  547.           (n->ln_Name[len] == '\0' ||
  548.           (n->ln_Name[len] == '.' && isdigits(&n->ln_Name[len+1]))))
  549.         {
  550.             return(n->ln_Name);
  551.         }
  552.     }
  553.  
  554.     return(NULL);
  555. }
  556.  
  557. /**************************************************************************/
  558.  
  559. static BOOL SendRexxMsg(struct MsgPort *replyport, STRPTR rxport, STRPTR rxcmd)
  560. {
  561.     struct HandlerMsg hm = {0};
  562.     hm.hm_Msg.mn_ReplyPort = replyport;
  563.     hm.hm_Msg.mn_Length    = sizeof(struct HandlerMsg);
  564.     hm.hm_Type             = HMT_AREXX;
  565.     hm.hm_ARexxPort        = rxport;
  566.     hm.hm_ARexxCmd         = rxcmd;
  567.  
  568.     /* check that the handler is still there */
  569.  
  570.     if(!AttemptSemaphore(&HandlerSemaphore))
  571.     {
  572.         /* yup, still there */
  573.  
  574.         PutMsg(HandlerMsgPort, (struct Message *)&hm);
  575.         WaitPort(replyport);
  576.         GetMsg(replyport);
  577.         return(hm.hm_Success);
  578.     }
  579.     else
  580.     {
  581.         /* eek, gone */
  582.  
  583.         ReleaseSemaphore(&HandlerSemaphore);
  584.         return(FALSE);
  585.     }
  586. }
  587.